package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.Objects;
import static com.example.gateway.constant.Constant.*;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;

/**
 * @author 谢飞机
 * @date   2021-08-25
 */
@Component
public class WebsocketFilter implements GlobalFilter, Ordered {



    /**
     * 请求流程 前端websocket 请求  ws://127.0.0.1:8888/websocket
     *
     * 路由经过网关配置的路由规则后  ws://127.0.0.1:8889/websocket
     *
     *  參考
     *  org.springframework.cloud.gateway.filter.WebsocketRoutingFilter
     *  主要逻辑：
     *  WebsocketRoutingFilter 类 转发ws的核心逻辑
     *  两种情况会处理
     *  1、upgrade 为 WebSocket 或者 webSocket  http
     *  2、https
     *  我们的请求是ws请求，需要将scheme 由ws转换成http，我们可以在此过滤器前，编写一个过滤器操作，也就是此类的filter方法中的核心逻辑
     *  if ("WebSocket".equalsIgnoreCase(upgrade) && ("http".equals(scheme) || "https".equals(scheme))) {
     * 			String wsScheme = convertHttpToWs(scheme);
     * 			boolean encoded = containsEncodedParts(requestUrl);
     * 			URI wsRequestUrl = UriComponentsBuilder.fromUri(requestUrl).scheme(wsScheme).build(encoded).toUri();
     * 			exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, wsRequestUrl);
     * 			if (log.isTraceEnabled()) {
     * 				log.trace("changeSchemeTo:[" + wsRequestUrl + "]");
     *   }
     *
     */

    /**
     *
     * @param exchange ServerWebExchange是一个HTTP请求-响应交互的契约。
     *                 提供对HTTP请求和响应的访问，
     *                 并公开额外的 服务器 端处理相关属性和特性，如请求属性
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

        String scheme = requestUrl.getScheme();

        if (!Objects.equals(WS_PROTOCOL,scheme) && !Objects.equals(WSS_PROTOCOL,scheme)) {

            return chain.filter(exchange);

        } else if (Objects.equals(DEFAULT_FILTER_PATH,requestUrl.getPath())) {

            scheme = convertWsToHttp(scheme);

            //TODO  uri: lb:ws://ws-server:8080/  方式的端口没有生效 手动赋值port  后续再研究
            URI wsRequestUrl = UriComponentsBuilder.fromUri(requestUrl).scheme(scheme).port(WS_SERVER_PORT).build().toUri();

            exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, wsRequestUrl);
        }
        return chain.filter(exchange);
    }


    /**
     * org.springframework.cloud.gateway.filter.WebsocketRoutingFilter
     * 这个类的order  Ordered.LOWEST_PRECEDENCE - 1
     * 此类需要在它之前就执行所以
     * Ordered.LOWEST_PRECEDENCE - 2;
     * @return
     */
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 2;
    }


    /**
     * 将HTTP 转换成 WS
     * @param scheme
     * @return
     */
    private String convertHttpToWs(String scheme) {

        scheme = scheme.toLowerCase();

        if(Objects.equals(HTTP_PROTOCOL,scheme)){

            return WS_PROTOCOL;

        }else if(Objects.equals(HTTPS_PROTOCOL,scheme)){

            return WSS_PROTOCOL;

        }else {

            return scheme;
        }

    }


    /**
     *  将 WS 转换成 HTTP
     * @param scheme
     * @return
     */
    private String convertWsToHttp(String scheme) {

        scheme = scheme.toLowerCase();

        if(Objects.equals(WS_PROTOCOL,scheme)){

            return HTTP_PROTOCOL;

        }else if(Objects.equals(WSS_PROTOCOL ,scheme)){

            return HTTPS_PROTOCOL;

        }else {

            return scheme;
        }

    }


}